<?php

namespace NorthernLights\JetBrainsLicensing;

use Cake\Utility\Xml as CakeXml;
use Cake\Utility\Exception\XmlException;
use NorthernLights\JetBrainsLicensing\Exception\XmlFactoryException;
use NorthernLights\JetBrainsLicensing\Exception\XmlGenerationException;

/**
 * Class XmlFactory
 * @package NorthernLights\JetBrainsLicensing
 */
class XmlFactory
{
    /** @var  \DOMDocument|null */
    private $domDocument;

    /** @var array */
    private $data;

    /** @var string */
    private $rootElm;

    /**
     * XmlFactory constructor.
     *
     * @param string $rootElement
     * @param array $data
     */
    public function __construct(string $rootElement, array $data = [])
    {
        $this->rootElm              = $rootElement;
        $this->data[$this->rootElm] = $data;
    }

    /**
     * Returns XML data if instance is used as a string
     *
     * @return string
     */
    public function __toString(): string
    {
        return ($this->domDocument !== null) ? $this->domDocument->saveXML() : '';
    }

    /**
     * Add element to XML
     *
     * @param string $element
     * @param mixed|null $value
     *
     * @return XmlFactory
     */
    public function add(string $element, $value = null): XmlFactory
    {
        $this->data[$this->rootElm][$element] = $value;

        return $this;
    }

    /**
     * Add multiple elements
     *
     * @param array $data
     *
     * @return XmlFactory
     */
    public function addMultiple(array $data): XmlFactory
    {
        $this->data[$this->rootElm] = array_merge($data, $this->data[$this->rootElm]);

        return $this;
    }

    /**
     * Remove XML element
     *
     * @param string $element
     *
     * @return XmlFactory
     */
    public function remove(string $element): XmlFactory
    {
        unset($this->data[$this->rootElm][$element]);

        return $this;
    }

    /**
     * Set DOMDocument properties
     *
     * @param string $name
     * @param $value
     *
     * @return XmlFactory
     * @throws XmlFactoryException
     */
    public function setDomDocumentOption(string $name, $value): XmlFactory
    {
        /** @var \DOMDocument $dom */
        $dom = $this->getDomDocument();

        if ( ! property_exists($dom, $name)) {
            throw new XmlFactoryException(
                sprintf('Option %s doesn\'t exist', $name)
            );
        }

        $dom->{$name} = $value;

        return $this;
    }

    /**
     * Build DomDocument from collected data
     *
     * @throws XmlException
     *
     * @return XmlFactory
     */
    public function build(): XmlFactory
    {
        $this->domDocument = CakeXml::build($this->data, [
            'return' => 'domdocument'
        ]);

        return $this;
    }

    /**
     * @return \DOMDocument
     *
     * @throws XmlFactoryException
     */
    public function getDomDocument()
    {
        if ($this->domDocument === null) {
            throw new XmlFactoryException('No DOMDocument created. Run: ' . __CLASS__ . '::build()');
        }

        return $this->domDocument;
    }

    /**
     * @return string
     */
    public function getXmlRoot(): string
    {
        return $this->rootElm;
    }

}